package com.richstonedt.smartcity.xaytsccommoncs.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.obs.services.ObsClient;
import com.obs.services.ObsConfiguration;
import com.obs.services.exception.ObsException;
import com.obs.services.model.*;
import com.richstonedt.smartcity.xaytsccommoncs.config.ObsProperties;
import com.richstonedt.smartcity.xaytsccommoncs.dao.FileStorageDao;
import com.richstonedt.smartcity.xaytsccommoncs.service.FileStorageService;
import com.richstonedt.smartcity.xaytsccommoncs.util.FileUtils;
import com.richstonedt.smartcity.xaytsccommoncs.util.ImageTypeCheck;
import com.richstonedt.smartcity.xaytsccommoncs.util.ObsUtil;
import com.richstonedt.smartcity.xaytsccommonms.FileStorageRuntimeException;
import com.richstonedt.smartcity.xaytsccommonms.model.FileStorage;
import com.richstonedt.smartcity.xaytsccommonms.params.BatchUrlQueryParams;
import com.richstonedt.smartcity.xaytsccommonms.params.BatchUrlQueryPerfectParams;
import com.richstonedt.smartcity.xaytsccommonms.params.FileUploadParams;
import com.richstonedt.smartcity.xaytsccommonms.params.ObsFileCommonParams;
import com.sun.corba.se.spi.ior.ObjectKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;


/**
 * <b><code>FileStorageServiceImpl</code></b>
 * <p/>
 * Description  通用-文件表 服务实现类
 * <p/>
 * <b>Creation Time:</b> 2022/3/29 15:56:45
 *
 * @author tangjiahuan
 * @since xaytsc-common-be
 */
@Service
public class FileStorageServiceImpl extends ServiceImpl<FileStorageDao, FileStorage> implements FileStorageService {

    private final ObsProperties obsProperties;

    private final Logger logger = LoggerFactory.getLogger(FileStorageServiceImpl.class);


    public FileStorageServiceImpl( ObsProperties obsProperties) {
        this.obsProperties = obsProperties;
    }


    @Override
    public List<FileStorage> upload(FileUploadParams params) {
        String creator = params.getCreator();
        String system = params.getSystemType();
        String baseUrl = StringUtils.isEmpty(params.getBaseUrl())?"":params.getBaseUrl();
        String bucketName = params.getBucketName();
        List<MultipartFile> files = params.getFiles();
        ArrayList<FileStorage> fileStorages = new ArrayList<>();
        ObsUtil obsUtil = new ObsUtil();
        try {
            initObsUtil(obsUtil);
            //文件夹不存在则创建
            String currentMonth = DateUtil.format(DateUtil.date(), "yyyyMM");
            baseUrl = baseUrl + currentMonth + "/";
            if(!obsUtil.isExistObject(params.getBucketName(),baseUrl)){
                obsUtil.createEmptyFolder(params.getBucketName(),baseUrl);
            }
            for (MultipartFile file : files) {
                FileStorage fileStorage = assembleFileStorage(file);
                fileStorage.setCreator(creator);
                fileStorage.setSystemType(system);
                fileStorage.setFilePath(baseUrl);
                String fileName = fileStorage.getFileName();
                obsUtil.setBucketName(bucketName);
                //文件夹 + 文件名（xaytsc-common-be/*****.jpg）
                String objectKey = baseUrl + fileName;
                PutObjectResult putObjectResult = obsUtil.putObjectAndSetPreAccessStrategy(objectKey, FileUtils.transferToFile(file),fileStorage.getIsImage());
                if (null == putObjectResult) {
                    continue;
                }
                fileStorage.setFileUrl(URLUtil.decode(putObjectResult.getObjectUrl()));
                if (this.baseMapper.insert(fileStorage) <= 0) {
                    //删除的对象
                    obsUtil.deletObj(objectKey);
                    continue;
                }
                fileStorages.add(fileStorage);
            }
            return fileStorages;
        }catch (ObsException e){
            obsUtil.outputErrorInfo(e);
            return null;
        }finally {
            closeObsUtil(obsUtil);
        }
    }

    @Override
    public List<String> deleteBatchFiles(String bucketName,String baseUrl,List<String> objectKeys) {
        if(null == objectKeys || objectKeys.size() == 0){
            throw new FileStorageRuntimeException("待删除文件对象key集合不可以为空!");
        }
        ArrayList<String> handleObjectKeys = new ArrayList<>();
        if(!StringUtils.isEmpty(baseUrl)){
            objectKeys.forEach(key-> handleObjectKeys.add(baseUrl + key));
        }
        ArrayList<String> list = new ArrayList<>();
        ObsUtil obsUtil = new ObsUtil();
        try {
            initObsUtil(obsUtil);
            obsUtil.setBucketName(bucketName);
            DeleteObjectsResult deleteObjectsResult = obsUtil.deleteBatch(bucketName,handleObjectKeys);
            for (DeleteObjectsResult.DeleteObjectResult obj:deleteObjectsResult.getDeletedObjectResults()) {
                String objectKey = obj.getObjectKey();
                objectKey = objectKey.substring(objectKey.lastIndexOf("/")+1);
                list.add(objectKey) ;
            }
            if(list.size() > 0){
                this.baseMapper.deleteBatchFileStorage(list);
            }
            return list;
        }catch (ObsException e){
            obsUtil.outputErrorInfo(e);
            return null;
        }finally {
            closeObsUtil(obsUtil);
        }
    }
    @Override
    public Boolean deleteFile(ObsFileCommonParams params) {
        boolean b;
        ObsUtil obsUtil = new ObsUtil();
        try {
            initObsUtil(obsUtil);
            obsUtil.setBucketName(params.getBucketName());
            String baseUrl = StringUtils.isEmpty(params.getBaseUrl())?"":params.getBaseUrl();
            b = obsUtil.deleteObject(baseUrl+params.getObjectKey());
            if(b){
                this.baseMapper.delete(new QueryWrapper<FileStorage>().eq("file_name", params.getObjectKey()));
                return true;
            }
            return false;
        }catch (ObsException e){
            obsUtil.outputErrorInfo(e);
            return false;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }finally {
            closeObsUtil(obsUtil);
        }
    }

    @Override
    public void downloadObject(ObsFileCommonParams params, HttpServletResponse response) {
        ObsUtil obsUtil = new ObsUtil();
        try{
            initObsUtil(obsUtil);
            obsUtil.setBucketName(params.getBucketName());
            String baseUrl = StringUtils.isEmpty(params.getBaseUrl())?"":params.getBaseUrl();
            String objectKey = baseUrl + params.getObjectKey();
            ObsObject obsObject = obsUtil.getObject(objectKey);
            FileStorage fileStorage = this.baseMapper.selectOne(new QueryWrapper<FileStorage>().eq("file_name", params.getObjectKey()));
            String fileName = fileStorage.getOriginalFileName();
            InputStream inputStream = obsObject.getObjectContent();
            if (inputStream != null){
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                try {
                    response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
                    response.setHeader("Content-Disposition","attachment; filename=" + URLUtil.encode(fileName));
                    FileUtils.writeBytes(inputStream, response.getOutputStream());
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }catch (ObsException e){
            obsUtil.outputErrorInfo(e);
        }finally {
            closeObsUtil(obsUtil);
        }
    }

    @Override
    public String getTemporarySignatureUrl(ObsFileCommonParams params) {
        ObsUtil obsUtil = new ObsUtil();
        try {
            TemporarySignatureResponse response;
            String bucketName = params.getBucketName();
            String baseUrl = StringUtils.isEmpty(params.getBaseUrl())?"":params.getBaseUrl();
            initObsUtil(obsUtil);
            obsUtil.setBucketName(bucketName);
            // URL有效期，1800秒（半个小时）
            long expireSeconds = 1800L;
            TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.GET, expireSeconds);
            request.setBucketName(bucketName);
            request.setObjectKey(baseUrl + params.getObjectKey());
            response = obsUtil.getObsClient().createTemporarySignature(request);
            /*if(fileStorage.getIsImage() == 0){
                // 设置图片转码参数
                Map<String,Object> queryParams = new HashMap<>(3);
                queryParams.put("x-image-process", "image/resize,m_fixed,w_100,h_100");
                request.setQueryParams(queryParams);
            }*/
            //获取支持图片转码的下载链接
            logger.info("Getting object using temporary signature url:"+"\t" + response.getSignedUrl());
            return response.getSignedUrl();
        }catch (ObsException e){
            obsUtil.outputErrorInfo(e);
            return null;
        }finally {
            closeObsUtil(obsUtil);
        }
    }

    @Override
    public Map<String,String> batchTemporarySignatureUrlPerfect(BatchUrlQueryPerfectParams params) {
        if(params.getObjectAndUrlMap() == null || params.getObjectAndUrlMap().size() == 0){
            return null;
        }
        ObsUtil obsUtil = new ObsUtil();
        try {
            initObsUtil(obsUtil);
            TemporarySignatureResponse response;
            String bucketName = params.getBucketName();
            HashMap<String, String> resultMap = new HashMap<>();
            obsUtil.setBucketName(bucketName);
            // URL有效期，1800秒（半个小时）
            long expireSeconds = 1800L;
            TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.GET, expireSeconds);
            request.setBucketName(bucketName);
           /* // 设置图片转码参数
            Map<String,Object> queryParams = new HashMap<>(3);
            queryParams.put("x-image-process", "image/resize,m_fixed,w_100,h_100");
            request.setQueryParams(queryParams);*/
            Map<String, String> objectAndUrlMap = params.getObjectAndUrlMap();
            for (String objectKey : objectAndUrlMap.keySet()) {
                String url = objectAndUrlMap.get(objectKey);
                String baseUrl = StringUtils.isEmpty(url)?"":url;
                request.setObjectKey(baseUrl + objectKey);
                response = obsUtil.getObsClient().createTemporarySignature(request);
                resultMap.put(objectKey,response.getSignedUrl());
                //获取支持图片转码的下载链接
                logger.info("Getting object using temporary signature url:"+"\t" + response.getSignedUrl());
            }
            return resultMap;
        }catch (ObsException e){
            obsUtil.outputErrorInfo(e);
            return null;
        }finally {
            closeObsUtil(obsUtil);
        }
    }


    @Override
    public Map<String,String> batchTemporarySignatureUrl(BatchUrlQueryParams params) {
        if(params.getObjectKeys() == null || params.getObjectKeys().size() == 0){
            return null;
        }
        ObsUtil obsUtil = new ObsUtil();
        try {
            initObsUtil(obsUtil);
            TemporarySignatureResponse response;
            String bucketName = params.getBucketName();
            String baseUrl = StringUtils.isEmpty(params.getBaseUrl())?"":params.getBaseUrl();
            HashMap<String, String> resultMap = new HashMap<>();
            obsUtil.setBucketName(bucketName);
            // URL有效期，1800秒（半个小时）
            long expireSeconds = 1800L;
            TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.GET, expireSeconds);
            request.setBucketName(bucketName);
           /* // 设置图片转码参数
            Map<String,Object> queryParams = new HashMap<>(3);
            queryParams.put("x-image-process", "image/resize,m_fixed,w_100,h_100");
            request.setQueryParams(queryParams);*/
            for (String objectKey:params.getObjectKeys()) {
                request.setObjectKey(baseUrl + objectKey);
                response = obsUtil.getObsClient().createTemporarySignature(request);
                resultMap.put(objectKey,response.getSignedUrl());
                //获取支持图片转码的下载链接
                logger.info("Getting object using temporary signature url:"+"\t" + response.getSignedUrl());
            }
            return resultMap;
        }catch (ObsException e){
            obsUtil.outputErrorInfo(e);
            return null;
        }finally {
            closeObsUtil(obsUtil);
        }
    }

    public FileStorage assembleFileStorage(MultipartFile file){
        FileStorage fileStorage = new FileStorage();
        fileStorage.setIsImage(ImageTypeCheck.isImage(file) ? 0 : 1);
        fileStorage.setFileSize(file.getSize());
        fileStorage.setOriginalFileName(file.getOriginalFilename());
        fileStorage.setFileExt(FileNameUtil.getSuffix(file.getOriginalFilename()));
        String fileName = IdUtil.objectId() + (StrUtil.isEmpty(fileStorage.getFileExt()) ? StrUtil.EMPTY : "." + fileStorage.getFileExt());
        fileStorage.setFileName(fileName);
        return fileStorage;
    }
    public void initObsUtil(ObsUtil obsUtil){
        ObsConfiguration config = new ObsConfiguration();
        config.setSocketTimeout(obsProperties.getSocketTimeout());
        config.setConnectionTimeout(obsProperties.getConnectionTimeout());
        config.setEndPoint(obsProperties.getEndPoint());
        ObsClient obsClient = new ObsClient(obsProperties.getAk(), obsProperties.getSk(), config);
        obsUtil.setObsClient(obsClient);
        logger.info("======obsService init========");
    }

    public void closeObsUtil(ObsUtil obsUtil){
        //关闭客户端连接
        if (obsUtil.getObsClient() != null) {
            try {
                obsUtil.getObsClient().close();
                logger.info("======closeClient========");
            } catch (IOException e) {
                e.printStackTrace();
                logger.error("[ "+this.getClass()+" - 关闭obs客户端连接失败 ]");
            }
        }
    }

}
